package main.bots;

import java.awt.Canvas;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Random;

import main.*;
import main.constants.Constants;
import main.hooks.RSArea;
import main.hooks.RSInterface;
import main.hooks.RSNPC;
import main.hooks.RSObject;
import main.hooks.RSPlayer;
import main.hooks.RSTile;

public class Methods extends client {

	/**
	 * ??
	 */
	private static final long serialVersionUID = 2580487288627061910L;
	
	public static Bank bank = new Bank();
	
	public static NpcShop npcShop = new NpcShop();
	
	private Random rand = new Random();
	
	public void say(String text) {
		getClientToUse().inputString = text;
		getClientToUse().sendEnterKey();
	}
	public Bank getBank() {
		return bank;
	}
	public static void clickMouse(Point p) {
		MouseHandler.clickMouse(p);
	}
	public static void clickMouse() {
		MouseHandler.clickMouse();
	}
	public static Canvas getCanvas() {
		return GUI.toUse.getCanvasToPaint();
	}
	public static void moveMouse(Point p) {
		MouseHandler.moveMouse(p);
	}
	public static void moveMouse(int x, int y) {
		MouseHandler.moveMouse(x, y);
	}
	/**
	 * Used to send a fake mouse click
	 */
	public void fakeMouse() {
		getStream().fakeMouse();
	}
	public void dropAllExcept(int[] ids) {
		RSInter class9_2 = RSInter.interfaceCache[Constants.INTERFACE_INVENTORY];
		if(class9_2 == null) {
			return;
		}
		for(int i = 0; i < class9_2.inv.length; i++) {
			for(int z = 0; z < ids.length; z++) {
			if(class9_2.inv[i] - 1 == ids[z] || class9_2.inv[i] + 1 == ids[z] || class9_2.inv[i] == ids[z]) {
				continue;
			}
			}
			if(class9_2.inv[i] == -1) continue;
			dropItem(class9_2.inv[i], i);
			wait(500);
			
		}
		
	}
	public boolean friendsListContains(String name) {
		for(int i = 0; i < getClientToUse().friendsCount; i++)
			if(getClientToUse().friendsListAsLongs[i] == TextClass.longForName(name))
			{
				return true;
			}
		return false;
	}
	public void addFriend(String name) {
		Methods.getClientToUse().addFriend(TextClass.longForName(name));
	}
	
	public static boolean friendOnline(String name) {
		for(int i = 0; i < getClientToUse().friendsListAsLongs.length; i++) {
			if(TextClass.longForName(name) != getClientToUse().friendsListAsLongs[i]) continue;
			return getClientToUse().friendsNodeIDs[i] == 10;
		}
		return false;
	}
	public void sendPm(String playerName, String message) {
		getStream().createFrame(126);
		getStream().writeWordBigEndian(0);
		int k = getStream().currentOffset;
		getStream().writeQWord(TextClass.longForName(playerName));
		getStream().writeBytes(getStream().currentOffset - k);
		getClientToUse().pushMessage(message, 6, TextClass.fixName(playerName));
	}
public RSPlayer[] getAllPlayers() {
		int size = 0;
		RSPlayer[] temp;
		ArrayList<RSPlayer> temp2 = new ArrayList<RSPlayer>();
		for(int i = 0; i < getMyClient().playerIndices.length; i++) {
			if(getMyClient().playerIndices[i] == 0)
				continue;
			Player playerTemp = getMyClient().playerArray[getMyClient().playerIndices[i]];
			if(playerTemp == null) {
			
				continue;
			}
		RSPlayer play = new RSPlayer(playerTemp, getMyClient().playerIndices[i]);
		if(play == null)
			continue;
		if(play.equals(getClientToUse().myPlayer)) continue;
			temp2.add(play);
		}
		temp2.trimToSize();
		temp = new RSPlayer[temp2.size()];
		int i = 0;
		for(RSPlayer p : temp2) {
			temp[i] = p;
			i = (i + 1);
		}
		return temp;
		}
		
	
	public RSPlayer getNearestPlayer() {
		RSPlayer temp = null;
		int distTo = 20;
		for(int i = 0; i < getMyClient().playerIndices.length; i++) {
			if(getMyClient().playerIndices[i] == 0)
				continue;
			Player playerTemp = getMyClient().playerArray[getMyClient().playerIndices[i]];
			if(playerTemp == null) {
			
				continue;
			}
		RSPlayer play = new RSPlayer(playerTemp, getMyClient().playerIndices[i]);
		if(play == null)
			continue;
		if(play.equals(getClientToUse().myPlayer)) continue;
		if(distanceTo(play.getLocation()) < distTo) {
			distTo = (int) distanceTo(play.getLocation());
			temp = play;
		}
	
		
		}
		return temp;
	}
	public Stream getStream() {
		return getClientToUse().stream;
	}
	public void tradeNPC(RSNPC toTrade) {
		if(toTrade == null) {
			throw new NullPointerException("toTrade is null");
		
		}
		fakeMouse();
		getStream().createFrame(230);
		getStream().writeWordBigEndian(239);
		anInt1226 = 0;
		getStream().createFrame(17);
		getStream().method433(toTrade.getSlotId());
	}
	public int[] getInventory() {
		return RSInter.interfaceCache[Constants.INTERFACE_INVENTORY].inv;
	}
	/**
	 * @param interfac - The level interface, getting all of them in Constants
	 * @return the skill level returned in the first slot of the interface, for example if you had 34/76 health, would return 34
	 */
	public int getRealSkillLevel(int interfac) {
		RSInterface skillInterface = getRSInterface(interfac);
		return Integer.parseInt(skillInterface.getText().trim());
	}
	public boolean inSquare(final int maxX, final int maxY, final int minX,
			final int minY) { // THANKS GARRETT!
		final int x = getMyLocation().getX();
		final int y = getMyLocation().getY();
		return x >= minX && x <= maxX && y >= minY && y <= maxY;
	}
	/**
	 * @return Returns true if inventory is full, else false
	 */
	public static boolean isInventoryFull() {
		if(!getClientToUse().loggedIn) {
			return false;
		}
		RSInter class9_2 = RSInter.interfaceCache[Constants.INTERFACE_INVENTORY];
		if(class9_2 == null) {
			return false;
		}
		for(int i = 0; i < class9_2.inv.length; i++) {
			if(class9_2.inv[i] == 0)
				return false;
		}
		return true;
	}
	public RSInterface getInterface(int id) {
		return new RSInterface(RSInter.interfaceCache[id]);
	}
	public void sendCommand(String s) {
		getClientToUse().stream.sendCommand(s);
	}
	public void clickFishSpot(int id) {
		getClientToUse().stream.clickFishSpot(id);
		
	}
	public boolean inventoryContains(int id) {
		RSInter class9_2 = RSInter.interfaceCache[Constants.INTERFACE_INVENTORY];
		if(class9_2 == null) {
			return false;
		}
		for(int i = 0; i < class9_2.inv.length; i++) {
			if(class9_2.inv[i] == id || class9_2.inv[i] - 1 == id || class9_2.inv[i] + 1 == id)
				return true;
		}
		return false;
	}
	/**
	 * @param interfac This is the interface of the level, check in constants class
	 * @return
	 */
	public int getSkillExp(int interfac) {
		RSInterface skillInterface = getRSInterface(interfac);
		return Integer.parseInt(skillInterface.getText().trim());
	}
	
	
	/**
	 * @param id The id of the interface
	 * @return Returns an RSInterface
	 */
	public RSInterface getRSInterface(int id) {
		return new RSInterface(RSInter.interfaceCache[id]);
	}
	public static int getInventorySlot(int id) {
		RSInter class9_2 = RSInter.interfaceCache[Constants.INTERFACE_INVENTORY];
		if(class9_2 == null) {
			return -1;
		}
		for(int i = 0; i < class9_2.inv.length; i++) {
			if(class9_2.inv[i] == id || class9_2.inv[i] - 1 == id || class9_2.inv[i] + 1 == id)
				return i;
		}
		return -1;
	}
	public int getItemInInventory(int slot) {
		RSInter class9_2 = RSInter.interfaceCache[Constants.INTERFACE_INVENTORY];
		if(class9_2 == null) {
			return -1;
		}
		return class9_2.inv[slot];
		
	}
	public RSNPC getClosestNpcToAttack(String name) {
		
		name = name.trim();
		for(int i = 0; i < getMyClient().npcIndices.length; i++) {
			if(getMyClient().npcIndices[i] == 0)
				continue;
			NPC npcTemp = getMyClient().npcArray[getMyClient().npcIndices[i]];
			if(npcTemp == null) {
			
				continue;
			}
		RSNPC npc = new RSNPC(npcTemp, getMyClient().npcIndices[i]);
		if(npc == null)
			continue;
		String s = npc.getName().trim();
		if(s.equalsIgnoreCase(name)) {
			System.out.println("Found npc: " + s);
			return npc;
		} else {
			
			continue;
		}
		}
		debug("No npc found");
		return null;
	}
	public RSNPC getNpcToAttackBySlotId(int slotId) {
			NPC npcTemp = getMyClient().npcArray[getMyClient().npcIndices[slotId]];
			if(npcTemp == null) {
				debug("No npc found at slot: " + slotId);
				return null;
			}
		return new RSNPC(npcTemp, getMyClient().npcIndices[slotId]);
	}
	public void wait(int toWait) {
		try {
			debug("Causing: " + Thread.currentThread().getName() + " to sleep for: " + toWait);
			Thread.sleep(toWait);
			debug("Done Sleeping");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void attackNpc(RSNPC toAttack) {
		if(toAttack == null){
			debug("toAttack wass null");
			return;
		}
			getMyClient().stream.attackNpc(toAttack.getSlotId());
	}
	public void walkTo(RSTile tile) {
		walkTo(tile.getX(), tile.getY());
	}
	public void walkTo(int x, int y) {
		
		//getClientToUse().walkTo(x, y);
		fakeMouse();
		WorldController.anInt470 = (x - getClientToUse().baseX);
		WorldController.anInt471 = (y - getClientToUse().baseY);
		//getClientToUse().doWalkTo(0, 0, 0, 0, (y - getClientToUse().baseY + 1), 0, 0, (y - getClientToUse().baseY), (x - getClientToUse().baseX) + 1, true, (x - getClientToUse().baseX));
		debug("Walking to: " + x + " and " + y);
	}
	public boolean onMap(RSTile t) {
		return distanceTo(t) < 10;
	}
	public RSTile getClosestTileInPath(RSTile[] inPath) {
		RSTile temp = null;
		int distTo = 20;
		for(int i = 0; i < inPath.length; i++) {
			if(inPath[i] == null) continue;
			if(inPath[i].getX() == getMyLocation().getX() && inPath[i].getY() == getMyLocation().getY()) continue;
			if(distanceTo(inPath[i]) < distTo) {
				if(distanceTo(inPath[inPath.length - 1]) < distanceBetween(inPath[i], inPath[inPath.length - 1])) {
					debug("Bad tile found: " + inPath[i].getX() + " y: " + inPath[i].getY());
					continue; //bad tile, its behind us :)
				}
				temp = inPath[i];
				distTo = (int) distanceTo(inPath[i]);
			}
		}
		System.out.println("Tile found: " + temp.getX() + " y: " + temp.getY());
		
		return temp;
	}
	public void walkPath(RSTile[] path) {
	
		RSTile closest = getClosestTileInPath(path);
		if(closest == null) {
			try {
				throw new Exception("closest tile was null");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return;
		}
		walkTo(closest);
	}
	public RSTile[] generatePath(RSTile toGo) {
		RSTile current = null;
		RSTile[] temp = new RSTile[100];
		int steps = 0;
		int distance = (int) distanceTo(toGo);
		debug("distance: " + distance);
		if(distance > 10) {
			current = toGo;
			while(current != toGo) {
				current = nextInPath(current, toGo);
				steps++;
			}
			temp = new RSTile[steps + 1];
		} else {
			//Its on map why make a path
			temp = new RSTile[1];
			temp[0] = toGo;
		}
		return temp;
	}
	private RSTile nextInPath(RSTile current, RSTile toGo) {
		int dist = distanceBetween(current, toGo);
		if(dist < 10)
			return toGo;
		return tileFrom(current, toGo, 8);
	}
	private RSTile tileFrom(RSTile current, RSTile inDirection, int i) {
		RSTile temp = current;
		int dist = distanceBetween(current, inDirection);
		return temp;
	}
	public void atInventoryItem(int id, int slot) {
		getClientToUse().stream.atInventoryItem(id, slot);
	}
	public void dropItem(int id, int slot) {
		getClientToUse().stream.dropItem(id, slot);
	}
	public void dropItem(int id) {
		dropItem(id, getInventorySlot(id));
	}
	public void openBank(RSTile bankLoc, int bankId) {
		atObject252(bankId, bankLoc.getX(), bankLoc.getY());
	}
	public RSTile randomTileInSquare(final int maxX, final int maxY, final int minX,final int minY) {
	return new RSTile(random(minX, maxX), random(minY, maxY));
	}
	public boolean isInCombat() {
		return getMyClient().myPlayer.loopCycleStatus > loopCycle;
	}
	public int getAnimation() {
		return client.myPlayer.anim;
	}
	public int getCurrentHealth() {
		return getMyClient().myPlayer.currentHealth;
	}
	public RSNPC getAllNPCSWithin(int dist) {
		RSNPC[] npcs = new RSNPC[100];
		for(int i = 0; i < getMyClient().npcArray.length; i++) {
			if(getMyClient().npcArray[i] == null)
				continue;
			if(distanceTo(getMyClient().npcArray[i].x, getMyClient().npcArray[i].y) <= dist)
				System.out.println("Npc found! " + getMyClient().npcArray[i].x + " and y: " + getMyClient().npcArray[i].y);
		}
		return null;
	}
	public void atObject(RSObject rsobj) {
		
	}
	public void atClosestRock(int rockId) {
		RSObject rock = getNearestObjectById(rockId);
		if(rock == null) {
			return;
		}
		atObject132(rock.getId(), rock.getX(), rock.getY());
	}
	public void atObject132(int objectId, int x, int y) {
		getClientToUse().method66(objectId, x - getClientToUse().baseX, y - getClientToUse().baseY);
		getStream().clickObject132(objectId, x, y);
	}
	public void atObject252(int objectId, int x, int y) {
		getClientToUse().stream.clickObject252(objectId, x, y);
		
	}
	public void atTree(RSObject tree) {
		atObject132(tree.getId(), tree.getX(), tree.getY());
	}
	@Deprecated
	public client getMyClient() {
		return getClientToUse();
	}
	public void debug(String s) {
		System.out.println("[" + getClass().getName() + " - " + Thread.currentThread().getName() + " - ] " + getTimeStamp() + " - " + s);
		
	}
	private String getTimeStamp() {
		return "";
	}
	public int random(int min, int max) {
		return rand.nextInt(Math.abs(max - min)) + min;
	}
	public RSTile randomTileInArea(RSArea a) {
		return a.getRandomTile();
	}
	public boolean inRSArea(RSArea area) {
		return inSquare(area.getMaxX(), area.getMaxY(), area.getMinX(), area.getMinY());
	}
	public RSTile getMyLocation() {
		return new RSTile(getMyClient().absX, getMyClient().absY);
	}
	public double distanceTo(RSTile tile) {
		return distanceTo(tile.getX(), tile.getY());
	}
	public static int distanceBetween(final RSTile t1, final RSTile t2) {
		return (int) Math.hypot(t2.getX() - t1.getX(), t2.getY() - t1.getY());
	}
	public double distanceTo(int x, int y) {
		return Math.hypot(x - getMyLocation().getX() , y - getMyLocation().getY());
	}
	
	public RSObject getNearestObjectById(int id) {
		int dist = 0;
		RSObject temp = null;
		System.out.println("Method called");
		for(int k = 0; k < Model.anInt1687; k++)
		{
			int l = Model.visibleModels[k];
			int k1 = l >> 29 & 3;
			int l1 = l >> 14 & 0x7fff;
		if(id != l1) {
			System.out.println("Filtered through: " + l1);
			continue;
		}
		System.out.println("Found: " + l1);
			int xCoord = (l & 0x7f) + getClientToUse().baseX;
			int yCoord = (l >> 7 & 0x7f) + getClientToUse().baseY;
			int distTo = (int) distanceTo(xCoord, yCoord);
			if(distTo < dist) {
				dist = distTo;
				temp = new RSObject(xCoord, yCoord, l1);
				continue;
			} else {
				continue;
			}
			
		}
		return temp;
	}
	
	public int getHealth() {
		return getMyClient().myPlayer.currentHealth;
	}
	
	

}
